package alexanderHash;



public class Hash {
    private Word[] array;
    private int noElements = 0;

    public Hash(int arraySize) {
        if (arraySize > 0)														/*1*/
            array = new Word[arraySize];
    }

    /**
     * Put a word in the hash and append the URL to
     * its list of URLs. Creates the word if it does
     * not already exist
     *
     * @param word The word to add
     * @param url  The URL were the word was found
     */
    public void put(String word, String url) {
        if (word == null || word.isEmpty())										/*1*/
            return;

        // Calculate a valid hash code
        int hashCode = Math.abs(word.hashCode()) % array.length;

        if (array[hashCode] == null) {											/*2*/
            // There is nothing at this index, so create a new entry
            Word w = new Word(word);
            w.urls = new URLlist(url);
            array[hashCode] = w;
            // We now have one more element in the hash
            ++noElements;
        } else {																
            // There is already something here, so check if
            // the word is already there
            Word current = array[hashCode];
            boolean doesExist = false;

            // Loop until we reach the end of the list (i.e.
            // the next element is null)
            while (current != null) {											/*3*/
                if (current.word.equals(word)) {								/*4*/
                    doesExist = true;
                    break;
                }

                current = current.next;
            }

            if (!doesExist) {													/*5*/
                // The word does not already exist, so create it
                Word w = new Word(word);
                w.urls = new URLlist(url);

                // The following two lines appends the new entry
                // onto the start just like we did in the previous
                // assignment
                w.next = array[hashCode];
                array[hashCode] = w;
                ++noElements;// TODO Auto-generated method stub
            } else {															/*6*/
                // The word already exists, try and add the url
                // Note that we don't increment the noElements
                // instance variable because we are not adding
                // another 'Word' object (it already exists), but
                // just appending the URL if it is not already there

                // There is no URLs associated with the entry, so add it
                if (current.urls == null)										/*7*/
                    current.urls = new URLlist(url);
                else {															
                    // There are already some URLs associated with the entry
                    // Check if the one we are adding is already there
                    URLlist currentUrl = current.urls;

                    while (currentUrl != null) {								/*8*/
                        // The URL already exists, so we can just return
                        if (currentUrl.url.equals(url))							/*9*/
                            return;

                        currentUrl = currentUrl.next;
                    }

                    // Add the URL in the same way we add 'Word' objects
                    URLlist urlNode = new URLlist(url);
                    urlNode.next = current.urls;
                    current.urls = urlNode;
                }
            }
        }
    }

    public URLlist getURLlist(String word) {
        int hashCode = Math.abs(word.hashCode()) % array.length;

        if (array[hashCode] == null)											/*1*/
            return null;

        Word current = array[hashCode];

        while (current != null) {												/*2*/
            if (current.word.equals(word))										/*3*/
                return current.urls;

            current = current.next;
        }

        return null;
    }

    public String getURLs(String word) {
        URLlist urlList = getURLlist(word);

        if (urlList == null)													/*1*/
            return "";

        String urls = "";

        while (urlList != null) {												/*2*/
            urls += urlList.url + "\n";
            urlList = urlList.next;
        }
        
        return urls;
    }

    // This method could be used in the put method, but it
    // recalculates the hash code. Alternatively, we could
    // make a private version that takes a hash code to avoid
    // this
    public boolean contains(String word) {
        int hashCode = Math.abs(word.hashCode()) % array.length;

        if (array[hashCode] == null)											/*1*/
            return false;

        Word current = array[hashCode];

        while (current != null) {												/*2*/
            if (current.word.equals(word))										/*3*/
                return true;

            current = current.next;
        }

        return false;
    }

    public void printKeyValuePairs() {
        for (int i = 0; i < array.length; ++i) {								/*1*/
            if (array[i] == null)												/*2*/
                continue;

            Word current = array[i];

            while (current != null) {											/*3*/
                System.out.println("Key => " + current.word);

                URLlist url = current.urls;

                while (url != null) {											/*4*/
                    System.out.println("\t" + url.url);
                    url = url.next;
                }

                current = current.next;
            }
        }
    }

    public int noElements() {
        return noElements;
    }

    // Equation: (number of total elements stored / length of array)
    // Not sure if the numerator should be the above or just the
    // number of non-empty entries in the hash
    public float loadFactor() {
        return ((float)noElements / (float)array.length);
    }
    
    
}
